﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Mail;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.VersionControl.Client;
using TFSMailer.Classes;
using System.Net;

namespace TFSMailer
{
    public partial class TfsMailer : Form
    {
        private static TeamFoundationServer _tfs;
        private static VersionControlServer _versionControl;
        private BackgroundWorker _workThread = new BackgroundWorker();
        private StringBuilder _mailNotSend;
        public TfsMailer()
        {
            InitializeComponent();
            _workThread.WorkerReportsProgress = true;
        }

        #region Properties.

        public String CurrentProject { get; set; }

        private static VersionControlServer VersionControl
        {
            get { return _versionControl; }
            set
            {
                if (_versionControl == null)
                {
                    _versionControl = value;
                }
            }
        }

        private static TeamFoundationServer Tfs
        {
            get { return _tfs; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (_tfs == null)
                {
                    _tfs = value;
                }
            }
        }

        #endregion

        private void Connect()
        {
            var dp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);
            DialogResult result = dp.ShowDialog();
            if (result == DialogResult.OK)
            {
                _versionControl = null;
                _tfs = null;
                CurrentProject = String.Empty;
                LoadInitialState(dp);

                settinToolStripMenuItem.Enabled = true;
                getUsersToolStripMenuItem.Enabled = true;
            }

            return;
        }

        /// <summary>
        /// Loads the initial state of TFS Mailer.
        /// </summary>
        /// <param name="dp">TeamProjectPicker dialog</param>
        private void LoadInitialState(TeamProjectPicker dp)
        {
            Tfs = TeamFoundationServerFactory.GetServer(dp.SelectedTeamProjectCollection.Name);
            Tfs.EnsureAuthenticated();
            VersionControl = (VersionControlServer)_tfs.GetService(typeof(VersionControlServer));
            CurrentProject = dp.SelectedProjects[0].ToString();

            cboProjects.Items.Clear();
            cboGroupsInProject.Items.Clear();
            listProjectUsers.Items.Clear();
            foreach (TeamProject tp in Projects.GetAllTeamProjects(VersionControl, false))
            {
                cboProjects.Items.Add(tp.Name);
            }

            if (String.IsNullOrEmpty(Properties.Settings.Default.FromMail))
            {
                Identity idCurrentUser = Users.GetUserInfo(Tfs, WindowsIdentity.GetCurrent().Name);
                txtFrom.Text = idCurrentUser.MailAddress;
            }
            else
            {
                txtFrom.Text = Properties.Settings.Default.FromMail;
            }
            cboProjects.SelectedItem = CurrentProject;


            Text = "TFS Mailer - " + _tfs.Name;


            Dictionary<string, Identity> listUsers = Users.GetGroupsInProject(_tfs, VersionControl, CurrentProject);

            if (listUsers != null)
            {
                cboGroupsInProject.Items.Add("All");
                foreach (var item in listUsers)
                {
                    Application.DoEvents();
                    cboGroupsInProject.Items.Add(item.Key);
                }
            }
        }


        private void AddListBoxUser(KeyValuePair<string, Identity> item)
        {
            Identity id = item.Value;

            if (chkShowUserWithoutMail.Checked)
            {
                listProjectUsers.Items.Add(new UserInformation(id.DisplayName, id.MailAddress));
            }
            else
            {
                if (!String.IsNullOrEmpty(id.MailAddress))
                {
                    listProjectUsers.Items.Add(new UserInformation(id.DisplayName, id.MailAddress));
                }
            }


            return;
        }

        private void cboGroupsInProject_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListUsersWithRolesOrAllUsers();
        }

        private static bool IsValidEmailAddress(string email)
        {
            try
            {
#pragma warning disable 168
                MailAddress ma = new MailAddress(email);
#pragma warning restore 168

                return true;
            }
            catch
            {
                return false;
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                if (String.IsNullOrEmpty(Properties.Settings.Default.SMTP))
                {
                    MessageBox.Show("You need to specify SMTP Server under File/Settings.", "Information",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                if (listProjectUsers.SelectedItems.Count == 0)
                {
                    MessageBox.Show("No user selected to mail.", "Information", MessageBoxButtons.OK,
                                    MessageBoxIcon.Information);
                    return;
                }

                if (!IsValidEmailAddress(txtFrom.Text))
                {
                    MessageBox.Show("Not valid from email address.", "Error mail address" + txtFrom.Text, MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    return;
                }

                SendMailToSelectedUsers();


                MessageBox.Show("Message Sent", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendMailToSelectedUsers()
        {
            _mailNotSend = new StringBuilder();
            var sb = new StringBuilder();
            int i;
            for (i = 0; i < listProjectUsers.SelectedItems.Count; i++)
            {
                string tempEmail = ((UserInformation)listProjectUsers.SelectedItems[i]).MailAddress;
                if (!String.IsNullOrEmpty(tempEmail))
                {
                    if (chkUniqueMail.Checked)
                    {
                        SendMail(tempEmail, ((UserInformation)listProjectUsers.SelectedItems[i]));
                    }
                    else
                    {
                        sb.Append(tempEmail);
                    }

                    if (i + 1 != listProjectUsers.SelectedItems.Count && !chkUniqueMail.Checked)
                    {
                        sb.Append(",");
                    }
                }
            }

            if (!chkUniqueMail.Checked)
            {
                SendMail(sb);
            }

            if (_mailNotSend.Length > 0)
            {
                MessageBox.Show("Mail that wasn't sent " + _mailNotSend + " of " + listProjectUsers.SelectedItems.Count + "mail. ");
            }
        }

        private void SendMail(StringBuilder sb)
        {
            try
            {
                var theClient = new SmtpClient(Properties.Settings.Default.SMTP);
                var msg = new MailMessage(txtFrom.Text, sb.ToString(), txtSubject.Text, txtBody.Text) { IsBodyHtml = false };
                
                
                if(!String.IsNullOrEmpty(Properties.Settings.Default.UserName))
                {
                    theClient.UseDefaultCredentials = false;
                    theClient.Credentials = new System.Net.NetworkCredential(Properties.Settings.Default.UserName, Properties.Settings.Default.Password);
                }
                
                theClient.Send(msg);
            }
            catch (Exception ex)
            {
                _mailNotSend.Append(ex.Message);
            }
        }

        private void SendMail(string userToMail, UserInformation userInfo)
        {
            try
            {
                var theClient = new SmtpClient(Properties.Settings.Default.SMTP);
                var msg = new MailMessage(txtFrom.Text, userToMail, txtSubject.Text,
                                          ParsePlaceHolders(txtBody.Text, userInfo.DisplayName)) { IsBodyHtml = false };
                //theClient.UseDefaultCredentials = false;
                //System.Net.NetworkCredential theCredential = new System.Net.NetworkCredential("user@name.com", "password");
                //theClient.Credentials = theCredential;
                theClient.Send(msg);
            }
            catch (Exception ex)
            {
                _mailNotSend.Append(userToMail + " " + userInfo.DisplayName + " " + userInfo.MailAddress + Environment.NewLine + ex.Message.ToString());
            }


        }

        private string ParsePlaceHolders(string body, string userName)
        {
            var reg = new Regex("#PROJECT");
            string newBody = reg.Replace(body, CurrentProject);
            var reg2 = new Regex("#USER");
            newBody = reg2.Replace(newBody, userName);
            return newBody;
        }

        private void settinToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var settings = new Settings();
            settings.Show(this);
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                Connect();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        private void ListUsersWithRolesOrAllUsers()
        {
            if (CheckThreadBusy())
            {
                return;
            }
            _workThread = new BackgroundWorker { WorkerReportsProgress = true };
            if (cboGroupsInProject.SelectedItem.Equals("All") ||
                String.IsNullOrEmpty(cboGroupsInProject.SelectedItem.ToString()))
            {
                var user = new Users();
                var uArgs = new UserThreadArgs
                                {
                                    Tfs = _tfs,
                                    Sourcecontrol = VersionControl,
                                    TeamProject = CurrentProject,
                                    Roles = ""
                                };
                _workThread.DoWork += user.GetUsersInProjectRole;
                _workThread.RunWorkerCompleted += WorkThreadRunWorkerCompleted;
                _workThread.ProgressChanged += WorkThreadProgressChanged;
                _workThread.RunWorkerAsync(uArgs);
            }
            else
            {
                var user = new Users();
                var uArgs = new UserThreadArgs
                                {
                                    Tfs = _tfs,
                                    Sourcecontrol = VersionControl,
                                    TeamProject = CurrentProject,
                                    Roles = cboGroupsInProject.SelectedItem.ToString()
                                };
                _workThread.DoWork += user.GetUsersInProjectRole;
                _workThread.RunWorkerCompleted += WorkThreadRunWorkerCompleted;
                _workThread.ProgressChanged += WorkThreadProgressChanged;
                _workThread.RunWorkerAsync(uArgs);
            }
        }

        private bool CheckThreadBusy()
        {
            if (_workThread.IsBusy)
            {
                return true;
            }
            return false;
        }


        public void WorkThreadRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled)
                {
                    _workThread = null;
                    MessageBox.Show("Task has been cancelled");
                }


                var listUsers = (Dictionary<string, Identity>)e.Result;
                listProjectUsers.Items.Clear();
                foreach (var item in listUsers)
                {
                    AddListBoxUser(item);
                }
            }
            catch (Exception)
            {
                MessageBox.Show(e.Error.Message);
            }
        }

        private void ListUsersInASpecificRole_Click(object sender, EventArgs e)
        {
            if (CheckThreadBusy())
            {
                return;
            }
            listProjectUsers.Items.Clear();
            cboGroupsInProject.Text = String.Empty;
            _workThread = new BackgroundWorker { WorkerReportsProgress = true };

            var user = new Users();
            var uArgs = new UserThreadArgs
                            {
                                Tfs = _tfs,
                                Sourcecontrol = VersionControl,
                                TeamProject = "",
                                Roles = ((ToolStripMenuItem)sender).Text
                            };
            _workThread.DoWork += user.GetAllUsersInProjectRole;
            _workThread.ProgressChanged += WorkThreadProgressChanged;

            _workThread.RunWorkerCompleted += WorkThreadRunWorkerCompleted;
            _workThread.RunWorkerAsync(uArgs);
        }

        public void WorkThreadProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Start progress..
            switch (e.ProgressPercentage)
            {
                case 0:
                    break;
                case 1:
                    break;
            }

            //Console.WriteLine(e.ProgressPercentage.ToString());
        }

        private void cboProjects_SelectionChangeCommitted(object sender, EventArgs e)
        {
            if (CheckThreadBusy())
            {
                return;
            }
            _workThread = new BackgroundWorker { WorkerReportsProgress = true };

            CurrentProject = cboProjects.SelectedItem.ToString();
            var user = new Users();
            var uArgs = new UserThreadArgs
                            {
                                Tfs = _tfs,
                                Sourcecontrol = VersionControl,
                                TeamProject = CurrentProject,
                                Roles = ""
                            };
            _workThread.DoWork += user.GetUsersList;
            _workThread.ProgressChanged += WorkThreadProgressChanged;

            _workThread.RunWorkerCompleted += WorkThreadRunWorkerCompleted;
            _workThread.RunWorkerAsync(uArgs);

            listProjectUsers.Items.Clear();

            if (cboGroupsInProject.Items.Count > 0)
            {
                cboGroupsInProject.SelectedIndex = 0;
            }
        }

        private void timerThreadCheck_Tick(object sender, EventArgs e)
        {
            toolStripProgressBar1.Style = CheckThreadBusy() ? ProgressBarStyle.Marquee : ProgressBarStyle.Blocks;
        }
    }

    /// <summary>
    /// User Information.
    /// </summary>
    public class UserInformation
    {
        public string DisplayName { get; set; }
        public string MailAddress { get; set; }

        public UserInformation()
        {
        }

        public UserInformation(string displayname, string mailadress)
        {
            DisplayName = displayname;
            MailAddress = mailadress;
        }

        public override string ToString()
        {
            return DisplayName + " [" + MailAddress + "]";
        }
    }
}
